﻿using System;
using System.Collections.Generic;

namespace Core.Res
{
    public partial class EditorLoader : Component, IAwake<EditorLoader.ApiMode>, ILoader
    {
        public enum ApiMode
        {
            AssetDatabase,
            Resource
        }

        private readonly Dictionary<string, Asset> assets = new();
        private readonly HashSet<string> missings = new();

        private PrefixDict mPrefixDict;
        private RelyQueue mQueue = new(10);

        public ApiMode APIMode { get; private set; }

        public void Awake(ApiMode mode)
        {
            APIMode = mode;

            mPrefixDict = APIMode switch
            {
                ApiMode.AssetDatabase => new PrefixDict($"Assets/Proj/Games/{G.Name}/"),
                ApiMode.Resource => new PrefixDict($"Games/{G.Name}/", true),
                _ => mPrefixDict
            };
        }

        public override void Dispose()
        {
            if (IsDisposed) return;
            base.Dispose();

            //TODO: 清理资源
        }

        public bool CheckAsset(string name)
        {
            return assets.ContainsKey(name) || missings.Contains(name);
        }

        public IAsset GetAsset(string name)
        {
            if (string.IsNullOrWhiteSpace(name)) return null;

            name = mPrefixDict[name];

            return assets.GetValueOrDefault(name);
        }

        public async ETTask<IAsset> LoadAsync(string name)
        {
            if (string.IsNullOrWhiteSpace(name)) return null;

            name = mPrefixDict[name];

            if (assets.ContainsKey(name) && mQueue.Contains(name) == false)
            {
                return assets[name];
            }

            var vo = new Asset(this);
            vo.SetInfo(name);
            vo.CreateAwaiter();

            await Enqueue(vo);

            return assets.GetValueOrDefault(name);
        }

        public IAsset LoadSync(string name)
        {
            if (string.IsNullOrWhiteSpace(name)) return null;

            name = mPrefixDict[name];

            if (assets.ContainsKey(name) && mQueue.Contains(name) == false)
            {
                return assets[name];
            }

            var vo = new Asset(this);
            vo.SetInfo(name);
            vo.LoadSync();

            return assets.GetValueOrDefault(name);
        }

        public async ETTask LoadAsync(IEnumerable<string> paths, Action<ILoadProgress> func)
        {
            if (paths == null) return;

            var dict = new Dictionary<string, Asset>();
            var lst = new List<string>();
            foreach (var item in paths)
            {
                string name = item;
                if (string.IsNullOrWhiteSpace(name))
                {
                    continue;
                }

                lst.Add(mPrefixDict[name]);
            }

            foreach (var item in lst)
            {
                if (dict.ContainsKey(item))
                {
                    continue;
                }

                var vo = new Asset(this);
                vo.SetInfo(item);
                dict[item] = vo;
            }

            var batch = new Batch(this);
            batch.CreateAwaiter();
            foreach (var item in dict)
            {
                batch.Rely.Add(item.Key);
                mQueue.Enqueue(item.Value);
            }

            func?.Invoke(batch);

            await Enqueue(batch);
        }

        private ETTask Enqueue(Asset vo)
        {
            mQueue.Enqueue(vo);
            return vo.Awaiter.Task;
        }

        private ETTask Enqueue(Batch vo)
        {
            mQueue.Enqueue(vo);
            return vo.Awaiter.Task;
        }

        public void Update()
        {
            mQueue.Update();
        }
    }
}
